package xt3FuturesUser

import (
	"context"
	"encoding/json"
	"math/rand"
	"sync"
	"time"
	"wscoin/common"

	"github.com/astaxie/beego/logs"
	jsoniter "github.com/json-iterator/go"
)

// 处理数据序列化和反序列化
// 相比内置序列化提高了性能和内存的开销
var jsonIteratorr = jsoniter.ConfigCompatibleWithStandardLibrary

// 数据解析
type RecvMessage struct {
	Channel string      `json:"channel"`
	Data    interface{} `json:"data"`
}

// 接收数据工厂
func NewRecvMessage(message []byte) *RecvMessage {

	recvMsg := new(RecvMessage)
	if string(message) == "pong" || string(message) == "succeed" {
		return recvMsg
	}
	err := json.Unmarshal(message, &recvMsg)
	if err != nil {
		logs.Info("[exchange-xt_contract_user-model] Unmarshal err ", err)
	}

	return recvMsg

}

// 判断数据是否正常
// 数据是否存在异常情况
// 数据是否为空
func (r RecvMessage) IsValid() bool {
	return r.Channel == ""
}

// Depth-Quant

type Bid []string
type Ask []string

type DepthDetail struct {
	Event         string `json:"e"`
	Time          int64  `json:"E"`
	Symbol        string `json:"s"`
	UpdateID      int64  `json:"u"`
	FirstUpdateID int64  `json:"U"`
	Bids          []Bid  `json:"b,omitempty"`
	Asks          []Ask  `json:"a,omitempty"`
}

type Depth struct {
	Stream string        `json:"stream"`
	Detail *DepthDetail  `json:"data"`
	Market common.Market `json:"m"`
}

// Unmarshal ---> recv depth
func (d *Depth) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Bids          interface{} `json:"bids"`
		Asks          interface{} `json:"asks"`
		Time          int64       `json:"ts"`
		MarketN       string      `json:"market"`
		FirstUpdateID int64       `json:"firstUpdateId"`
		UpdateID      int64       `json:"UpdateId"`
	}{
		Bids:          BidsFormat(d.Detail.Bids), // [{"price":'', "amount":'', "type":""}]
		Asks:          AsksFormat(d.Detail.Asks), // [{"price":'', "amount":'', "type":""}]
		Time:          d.Detail.Time,
		MarketN:       d.Market.Symbol,
		FirstUpdateID: d.Detail.FirstUpdateID,
		UpdateID:      d.Detail.UpdateID,
	})

}

// 解析的Depth数据是否有效
func (d *Depth) IsValid() bool {
	isCheck := (d.Detail != nil &&
		d.Detail.Event != "") && (len(d.Detail.Asks) != 0 ||
		len(d.Detail.Bids) != 0)
	return isCheck
}

// Update-Market
func (d *Depth) MarketAssign(symbol string) {
	d.Market.MarketAssign(symbol)
}

// Kline-Detail
type KlineDetail struct {
	Open   string      `json:"o"`
	High   string      `json:"h"`
	Low    interface{} `json:"l"`
	Close  string      `json:"c"`
	Volume string      `json:"v"`
}

type KlineDiv struct {
	Event       string       `json:"e"`
	Symbol      string       `json:"s"`
	Time        int64        `json:"E"`
	KlineDetail *KlineDetail `json:"k"`
}

type Kline struct {
	Stream   string        `json:"stream"`
	KlineDiv *KlineDiv     `json:"data"`
	Market   common.Market `json:"m"`
}

// Kline
func (k *Kline) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Open    string      `json:"open"`
		High    string      `json:"high"`
		Low     interface{} `json:"low"`
		Close   string      `json:"close"`
		Volume  string      `json:"volume"`
		Time    int64       `json:"ts"`
		MarketN string      `json:"market"`
	}{
		Open:    k.KlineDiv.KlineDetail.Open,
		High:    k.KlineDiv.KlineDetail.High,
		Low:     k.KlineDiv.KlineDetail.Low,
		Close:   k.KlineDiv.KlineDetail.Close,
		Volume:  k.KlineDiv.KlineDetail.Volume,
		Time:    k.KlineDiv.Time,
		MarketN: k.Market.Symbol,
	})
}

// Ticker-Detail
type TickerDetail struct {
	UpdateId int64  `json:"u"`
	Symbol   string `json:"s"`
	BidPrice string `json:"b"`
	BidQty   string `json:"B"`
	AskPrice string `json:"a"`
	AskQty   string `json:"A"`
}

type Ticker struct {
	Stream       string        `json:"stream"`
	TickerDetail *TickerDetail `json:"data"`
	Market       common.Market `json:"m"`
}

// Ticker Marshal
func (t *Ticker) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Symbol   string `json:"symbol"`
		BidPrice string `json:"bidPrice"`
		BidQty   string `json:"bidQty"`
		AskPrice string `json:"askPrice"`
		AskQty   string `json:"askQty"`
		MarketN  string `json:"market"`
		UpdateId int64  `json:"updateId"`
	}{
		Symbol:   t.TickerDetail.Symbol,
		BidPrice: t.TickerDetail.BidPrice,
		BidQty:   t.TickerDetail.BidQty,
		AskPrice: t.TickerDetail.AskPrice,
		AskQty:   t.TickerDetail.AskQty,
		MarketN:  t.Market.Symbol,
		UpdateId: t.TickerDetail.UpdateId,
	})
}

// 解析的Depth数据是否有效
func (t *Ticker) IsValid() bool {
	isCheck := t.TickerDetail != nil
	return isCheck
}

// Update-Market
func (t *Ticker) MarketAssign(symbol string) {
	t.Market.MarketAssign(symbol)
}

// Trade-Detail
type QuotationDetail struct {
	Event     string      `json:"e"`
	EventTime int64       `json:"E"`
	Time      int64       `json:"T"`
	Symbol    string      `json:"s"`
	Trade     int64       `json:"t"`
	Price     interface{} `json:"p"`
	Quotation interface{} `json:"q"`
	BidID     int64       `json:"b"`
	AskID     int64       `json:"a"`
	MT        bool        `json:"m"`
	M         bool        `json:"M"`
}

type Quotation struct {
	Stream          string           `json:"stream"`
	QuotationDetail *QuotationDetail `json:"data"`
	Market          common.Market    `json:"mk"`
}

func boolToInt(value bool) string {
	if value {
		return "buy"
	} else {
		return "sell"
	}
}

// Quotation Marshal
func (q *Quotation) MarshalJSON() ([]byte, error) {
	return json.Marshal(struct {
		Symbol    string      `json:"symbol"`
		LastPrice interface{} `json:"lastPrice"`
		Time      int64       `json:"ts"`
		Quotation interface{} `json:"quotation"`
		MarketN   string      `json:"market"`
		TradeID   int64       `json:"id"`
		BuyId     int64       `json:"buyId"`
		SellId    int64       `json:"sellId"`
		Side      string      `json:"side"`
	}{
		Symbol:    q.QuotationDetail.Symbol,
		LastPrice: q.QuotationDetail.Price,
		Time:      q.QuotationDetail.Time,
		Quotation: q.QuotationDetail.Quotation,
		MarketN:   q.Market.Symbol,
		TradeID:   q.QuotationDetail.Trade,
		BuyId:     q.QuotationDetail.BidID,
		SellId:    q.QuotationDetail.AskID,
		Side:      boolToInt(q.QuotationDetail.MT),
	})
}

// 解析的Depth数据是否有效
func (q *Quotation) IsValid() bool {
	isCheck := q.QuotationDetail != nil
	return isCheck
}

func (q *Quotation) MarketAssign(symbol string) {
	q.Market.MarketAssign(symbol)
}

// 定义快照model
type OrderBook struct {
	Amount string `json:"amount,omitempty"`
	Price  string `json:"price,omitempty"`
}

type CacheDepth struct {
	Bids          []OrderBook `json:"bids"`
	Asks          []OrderBook `json:"asks"`
	Time          int64       `json:"ts"`
	Market        string      `json:"market"`
	FirstUpdateID int64       `json:"firstUpdateId"`
	UpdateID      int64       `json:"UpdateId"`
	Mu            sync.Mutex
	control       bool
}

func (d *CacheDepth) Limit() {
	d.Mu.Lock()
	defer d.Mu.Unlock()
	d.control = true
}

func (d *CacheDepth) IsLimit() bool {
	return d.control
}

func (d *CacheDepth) LimitCancel() {
	d.Mu.Lock()
	defer d.Mu.Unlock()
	d.control = false
}

func (d *CacheDepth) ResetLimit(ctx context.Context) {
	go func() {
		for {
			select {
			case <-ctx.Done():
				logs.Info("[xt_contract_user-model-limit] ReadMessage exit ...", d.Market)
				return
			default:
				//
			}
			if d.IsLimit() {
				rand.Seed(time.Now().Unix())
				d.LimitCancel()
				time.Sleep(time.Second * 2 * time.Duration(rand.Int63n(10)))
				logs.Debug("[xt_contract_user-model-limit] >>> limit cancel ...", d.Market)
			}
			time.Sleep(time.Second * 3)

		}
	}()
}
